package tbs.framework.utils;

import org.jetbrains.annotations.NotNull;
import tbs.framework.interfaces.FunctionWithThrows;
import tbs.framework.interfaces.RunableWithThrows;

/**
 * IWrapper接口用于封装一个函数及其参数，提供安全执行和异常处理的功能
 * 它定义了如何安全地执行一个可能抛出异常的函数，并提供了执行void类型函数的方法
 *
 * @param <R> 函数返回值类型
 * @param <P> 函数参数类型
 * @param <A1> 附加参数1类型
 * @param <A2> 附加参数2类型
 * @param <E> 可能抛出的异常类型
 */
public interface IWrapper<R, P, A1, A2, E extends Throwable> {

    /**
     * 执行一个可能抛出异常的函数，并接受两个附加参数
     *
     * @param function 要执行的函数，可能抛出异常
     * @param param 函数的参数
     * @param arg1 附加参数1
     * @param arg2 附加参数2
     * @return 函数的返回值
     * @throws E 如果执行函数时抛出异常，则抛出该异常
     */
    public R wrap(@NotNull FunctionWithThrows<P, R, E> function, P param, A1 arg1, A2 arg2) throws E;

    /**
     * 安全地执行一个可能抛出异常的函数，任何异常都会被捕获，不会向外抛出
     *
     * @param function 要安全执行的函数，可能抛出异常
     * @param param 函数的参数
     * @param arg1 附加参数1
     * @param arg2 附加参数2
     * @return 函数的返回值，如果执行过程中捕获异常，则返回null
     */
    public default R wrapSafely(@NotNull FunctionWithThrows<P, R, E> function, P param, A1 arg1, A2 arg2) {
        Object[] result = new Object[1];
        TryCatchUtils.tryCatch(() -> {
            result[0] = wrap(function, param, arg1, arg2);
            return;
        }, null, null);
        return (R)result[0];
    }

    /**
     * 执行一个可能抛出异常的void类型函数，并接受两个附加参数
     *
     * @param function 要执行的void类型函数，可能抛出异常
     * @param arg1 附加参数1
     * @param arg2 附加参数2
     * @throws E 如果执行函数时抛出异常，则抛出该异常
     */
    public default void wrapVoid(@NotNull RunableWithThrows function, A1 arg1, A2 arg2) throws E {
        wrap(p -> {
            function.run();
            return null;
        }, null, arg1, arg2);
    }

    /**
     * 安全地执行一个可能抛出异常的void类型函数，任何异常都会被捕获，不会向外抛出
     *
     * @param function 要安全执行的void类型函数，可能抛出异常
     * @param arg1 附加参数1
     * @param arg2 附加参数2
     */
    public default void wrapVoidSafely(@NotNull RunableWithThrows function, A1 arg1, A2 arg2) {
        wrapSafely(p -> {
            function.run();
            return null;
        }, null, arg1, arg2);
    }
}
